﻿Imports System.Drawing.Drawing2D
Imports Microsoft.Win32
Imports System.IO
Imports System.Runtime.InteropServices
Imports Microsoft.Win32.Registry
Imports System.Text.RegularExpressions
Imports IWshRuntimeLibrary

''' <summary>
''' A class which has common tools that are necessary for programming.
''' </summary>
Public Class CommonTools

    ''' <summary>
    ''' Get disabled style of an image.
    ''' </summary>
    ''' <param name="Image">The image that you want to convert it to disabled style.</param>
    Public Shared Function GetDisabledImage(ByVal Image As Image)
        Dim ir As New Bitmap(Image.Width, Image.Height)
        Dim Gr As Graphics = Graphics.FromImage(ir)
        ControlPaint.DrawImageDisabled(Gr, Image, 0, 0, Color.Transparent)
        Gr.Dispose()
        Return ir
    End Function
    ''' <summary>
    ''' Are 2 images the same (identical)?
    ''' </summary>
    ''' <param name="originalImage" >First image.</param>
    ''' <param name="compareToImage" >Second image.</param>
    Private Function DoImagesMatch(ByVal OriginalImage As Bitmap, ByVal CompareToImage As Bitmap) As Boolean
        'first check the image sizes, if 
        'they dont match return false
        If Not (OriginalImage.Size = CompareToImage.Size) Then
            Return False
        Else
            'create 2 loops, loop for the image height
            'and one for the image width
            For i As Integer = 0 To OriginalImage.Width - 1
                For j As Integer = 0 To OriginalImage.Height - 1
                    'compare each pixel, if we find one that doesnt match
                    'then return false we're done
                    If OriginalImage.GetPixel(i, j) <> CompareToImage.GetPixel(i, j) Then
                        Return False
                    End If
                Next
            Next
            'we made it this far so the images match
            Return True
        End If
    End Function

    ''' <summary>
    ''' Gets or sets a member of a class with name of it.
    ''' </summary>
    Public Class StringMember
        Inherits StringMember(Of Object)
    End Class

    ''' <summary>
    ''' Gets or sets a member of a class with name of it.
    ''' </summary>
    ''' <typeparam name="T">Type of member.</typeparam>
    Public Class StringMember(Of T)
        ''' <summary>
        ''' Gets or sets a class that has this member.
        ''' </summary>
        Public Property ParentClass As Object
        ''' <summary>
        ''' Gets or sets name of this member.
        ''' </summary>
        Public Property MemberName As String
        ''' <summary>
        ''' Gets or sets this member.
        ''' </summary>
        Public Property Value As T
            Get
                Return GetValue()
            End Get
            Set(ByVal SetValue As T)
                GetValue()
                Try
                    ' CallByName(ParentClass, MemberName, CallType.Set, value) 
                    AccessValue(Of T)(Me, SetValue)
                Catch ex As ArgumentException
                    If ex.Message <> "Destination array was not long enough. Check destIndex and length, and the array's lower bounds." Then
                        Throw ex
                    Else
                        SetMyValue(SetValue)
                    End If
                End Try
            End Set
        End Property

        Private Delegate Sub AccessValueDelegate(Of T)(ByVal PA As StringMember(Of T), ByVal Value As T)
        Friend Shared Sub AccessValue(Of T)(ByVal PA As StringMember(Of T), ByVal Value As T)
            If TypeOf PA.ParentClass Is Control AndAlso PA.ParentClass.InvokeRequired Then
                CType(PA.ParentClass, Control).Invoke(New AccessValueDelegate(Of T)(AddressOf AccessValue(Of T)), PA, Value)
            Else
                Try
                    CallByName(PA.ParentClass, PA.MemberName, CallType.Set, Value)
                Catch ex As ArgumentException
                    If ex.Message <> "Destination array was not long enough. Check destIndex and length, and the array's lower bounds." Then
                        Throw ex
                    Else
                        AccessValue(Of T)(PA, Value)
                    End If
                End Try
            End If
        End Sub
        Private Sub SetMyValue(ByVal SetValue As T)
            Value = SetValue
        End Sub

        Private Function GetValue() As T
            Try
                Return CallByName(ParentClass, MemberName, CallType.Get)
            Catch ex As InvalidCastException
                Throw New InvalidCastException("The type of member (It got from MemberName) must be a " + GetType(T).Name + ".")
            Catch ex As MissingMemberException
                Throw New MissingMemberException(ParentClass.GetType().Name, MemberName)
            End Try
        End Function
    End Class
#Region "Extract MsgBox"
    ''' <summary>
    ''' A class that properties of a dialog store on it.
    ''' In Common Tools,it use to extract options of MsgBoxStyles.
    ''' </summary>
    Class DialogOptions
        Public Icon As MsgBoxStyle
        Public Buttons As MsgBoxStyle
        Public DefaultButton As MsgBoxStyle
        Public DoesHaveItDefaultButton As Boolean = True
        Public Property RightToLeft As Boolean
        Public Property RightToLeftLayout As Boolean
        Public Property Help As Boolean
        Public Property SystemModal As Boolean
        Public Property ApplicationModal As Boolean
        ''' <summary>
        ''' Gets or sets base MsgBoxStyle object (additional options).
        ''' </summary>
        Public Property BaseStyle As MsgBoxStyle
    End Class
    ''' <summary>
    ''' Extract properties of a MsgBoxStyle object.
    ''' </summary>
    ''' <param name="Options">Properties that are stored on a MsgBoxStyle object.</param>
    Public Function ExtractOptionsOfMsgBoxStyle(ByVal Options As MsgBoxStyle) As DialogOptions
        Dim Eo As New DialogOptions
        If Options And MsgBoxStyle.Critical Then
            Eo.Icon = MsgBoxStyle.Critical
        ElseIf Options And MsgBoxStyle.Exclamation Then
            Eo.Icon = MsgBoxStyle.Exclamation
        ElseIf Options And MsgBoxStyle.Information Then
            Eo.Icon = MsgBoxStyle.Information
        ElseIf Options And MsgBoxStyle.Question Then
            Eo.Icon = MsgBoxStyle.Question
        End If
        If Options And MsgBoxStyle.OkOnly Then
            Eo.Buttons = MsgBoxStyle.OkOnly
        ElseIf Options And MsgBoxStyle.OkCancel Then
            Eo.Buttons = MsgBoxStyle.OkCancel
        ElseIf Options And MsgBoxStyle.AbortRetryIgnore Then
            Eo.Buttons = MsgBoxStyle.AbortRetryIgnore
        ElseIf Options And MsgBoxStyle.RetryCancel Then
            Eo.Buttons = MsgBoxStyle.RetryCancel
        ElseIf Options And MsgBoxStyle.YesNo Then
            Eo.Buttons = MsgBoxStyle.YesNo
        ElseIf Options And MsgBoxStyle.YesNoCancel Then
            Eo.Buttons = MsgBoxStyle.YesNoCancel
        End If
        If Options And MsgBoxStyle.DefaultButton1 Then
            Eo.DefaultButton = MsgBoxStyle.DefaultButton1
        ElseIf Options And MsgBoxStyle.DefaultButton2 Then
            Eo.DefaultButton = MsgBoxStyle.DefaultButton2
        ElseIf Eo.DefaultButton = MsgBoxStyle.DefaultButton3 Then
            Eo.DefaultButton = MsgBoxStyle.DefaultButton3
        Else
            Eo.DoesHaveItDefaultButton = False
        End If
        Eo.RightToLeft = Options And MsgBoxStyle.MsgBoxRight
        If Options And MsgBoxStyle.MsgBoxRtlReading Then
            Eo.RightToLeft = True
            Eo.RightToLeftLayout = True
        End If
        Eo.Help = Options And MsgBoxStyle.MsgBoxHelp
        Eo.SystemModal = Options And MsgBoxStyle.SystemModal
        Eo.ApplicationModal = Options And MsgBoxStyle.ApplicationModal
        Eo.BaseStyle = Options
        Return Eo
    End Function
#End Region
    ''' <summary>
    ''' Get location of a control in the Form.
    ''' </summary>
    ''' <param name="Control">The control that you want its actual location.</param>
    <Extension()>
    Public Shared Function GetActualLocation(ByVal Control As Control) As Point
        Dim f As Form = Nothing
        Dim l As New Point(Control.Left, Control.Top)
        While (InlineAssignHelper(Control, Control.Parent)) IsNot Nothing
            f = TryCast(Control, Form)
            If f IsNot Nothing Then
                Return l
            Else
                l.Y += Control.Top
                l.X += Control.Left
            End If
        End While
    End Function
    ''' <summary>
    ''' Set location of a control in Form.
    ''' </summary>
    ''' <param name="Control">The control that you want to set its location.</param>
    <Extension()>
    Public Shared Sub SetActualLocation(ByVal Control As Control)
        Dim f As Form = Nothing
        Dim TControl As Control = Control
        While (InlineAssignHelper(Control, Control.Parent)) IsNot Nothing
            f = TryCast(Control, Form)
            If f IsNot Nothing Then
                TControl.Parent = f
                TControl.BringToFront()
            Else
                TControl.Top += Control.Top
                TControl.Left += Control.Left
                TControl.Parent = Control
            End If
        End While
    End Sub
    ''' <summary>
    ''' Get a control that has actual location of inputed control.
    ''' </summary>
    ''' <param name="Control">The control that you want to get its actual location.</param>
    <Extension()>
    Public Shared Function GetActualLocationAsControl(ByVal Control As Control) As Control
        Dim Temp As New Control
        Temp.Location = GetActualLocation(Control)
        Temp.Size = Control.Size
        Return Temp
    End Function
    ''' <summary>
    ''' Get parent Form of a control.
    ''' </summary>
    ''' <param name="Control">The control that you want its parent Form.</param>
    <Extension()>
    Public Shared Function GetParentForm(ByVal Control As Control) As Form
        Dim f As Form = Nothing
        While (InlineAssignHelper(Control, Control.Parent)) IsNot Nothing
            f = TryCast(Control, Form)
            If f IsNot Nothing Then
                Return f
            End If
        End While
        Return Nothing
    End Function
    Private Shared Function InlineAssignHelper(Of T)(ByRef Target As T, ByVal Value As T) As T
        Target = Value
        Return Value
    End Function
    ''' <summary>
    ''' Set right of a control (not "Right" property,the distance between right edge of control and right edge of its parent.)
    ''' </summary>
    ''' <param name="Control">The control that you want to set its right.</param>
    ''' <param name="Right">Value of Control's right.</param>
    ''' <remarks></remarks>
    <Extension()>
    Shared Sub SetRight(ByVal Control As Control, ByVal Right As Integer)
        Control.Left = Control.Parent.Width - Control.Width - Right
    End Sub
    <Extension()>
    Shared Function GetRight(ByVal Control As Control) As Integer
        Return Control.Parent.Width - Control.Right
    End Function
    Public Shared ReadOnly Property VistaBlue As Color
        Get
            Return Color.FromArgb(255, 0, 75, 153)
        End Get
    End Property
    Public Shared ReadOnly Property DarkVistaBlue As Color
        Get
            Return Color.FromArgb(255, 21, 28, 85)
        End Get
    End Property
    Public Shared ReadOnly Property LightVistaBlue As Color
        Get
            Return Color.FromArgb(255, 7, 74, 229)
        End Get
    End Property
    Public Shared ReadOnly Property DeactiveBasicThemeColor As Color
        Get
            Return Color.FromArgb(255, 215, 228, 242)
        End Get
    End Property
    Public Shared ReadOnly Property ActiveBasicThemeColor As Color
        Get
            Return Color.FromArgb(255, 185, 209, 234)
        End Get
    End Property
    ''' <summary>
    ''' Gets Is current OS Windows Vista or later?
    ''' </summary>
    Public Shared ReadOnly Property AeroSupport As Boolean
        Get
            Return Environment.OSVersion.Version.Major >= 6
        End Get
    End Property
    ''' <summary>
    ''' Gets best color for Aero area in Windows XP or in Basic theme.
    ''' </summary>
    ''' <param name="Focused">A value that show Form is active or not.</param>
    ''' <param name="AeroEnabled">A value that if be true,return AeroColor.</param>
    ''' <param name="AeroColor">A value that it return if AeroEnabled be false.</param>
    Public Shared Function GetAeroAreaColor(ByVal Focused As Boolean, Optional ByVal AeroEnabled As Boolean = False, Optional ByVal AeroColor As Color = Nothing) As Color
        If AeroColor = Nothing Then
            AeroColor = Color.Black
        End If
        If AeroEnabled Then
            Return AeroColor
        Else
            If AeroSupport AndAlso IsBasicTheme Then
                ' If ThemeInfo.CurrentTheme.ColorSchemeName = "Basic" Then
                If Focused Then
                    Return ActiveBasicThemeColor
                Else
                    Return DeactiveBasicThemeColor
                End If
            Else
                If Focused Then
                    Return SystemColors.ActiveCaption
                Else
                    Return SystemColors.InactiveCaption
                End If
            End If
        End If
    End Function
    ''' <summary>
    ''' Gets is Basic theme active.
    ''' </summary>
    Public Shared ReadOnly Property IsBasicTheme As Boolean
        Get
            If ThemeInfo.CurrentTheme.FileName IsNot Nothing AndAlso AeroSupport Then
                Dim finfo As New IO.FileInfo(ThemeInfo.CurrentTheme.FileName)
                Return IO.Path.GetFileNameWithoutExtension(finfo.Name).ToLower = "aero" _
                        AndAlso finfo.Directory.Name.ToLower = "aero"
            Else
                Return False
            End If
        End Get
    End Property
    ''' <summary>
    ''' Get TextFormatFlags of a label.
    ''' </summary>
    ''' <param name="Label" >A Label that its options use to create a TextFormatFlags.</param>
    Public Shared Function GetTextFormatFlags(ByVal Label As Label) As TextFormatFlags
        Return GetTextFormatFlags(Label.TextAlign, Label.RightToLeft, Label.Text, Label.UseMnemonic)
    End Function
    ''' <summary>
    ''' Get TextFormatFlags of a label.
    ''' </summary>
    ''' <param name="TextAlign">TextAlign of label.</param>
    ''' <param name="RightToLeft">RightToLeft of Label.</param>
    ''' <param name="Text">Text of Label.</param>
    ''' <param name="UseMnemonic">Is UseMnemonic of text enabled?</param>
    Public Shared Function GetTextFormatFlags(ByVal TextAlign As ContentAlignment, Optional ByVal RightToLeft As RightToLeft = Windows.Forms.RightToLeft.No, Optional ByVal Text As String = "", Optional ByVal UseMnemonic As Boolean = False) As TextFormatFlags
        Dim LabelAlign As TextFormatFlags
        Select Case TextAlign
            Case Drawing.ContentAlignment.BottomCenter
                LabelAlign = TextFormatFlags.Bottom Or TextFormatFlags.HorizontalCenter
            Case Drawing.ContentAlignment.BottomLeft
                LabelAlign = TextFormatFlags.Bottom Or TextFormatFlags.Left
            Case Drawing.ContentAlignment.BottomRight
                LabelAlign = TextFormatFlags.Bottom Or TextFormatFlags.Right
            Case Drawing.ContentAlignment.MiddleCenter
                LabelAlign = TextFormatFlags.VerticalCenter Or TextFormatFlags.HorizontalCenter
            Case Drawing.ContentAlignment.MiddleLeft
                LabelAlign = TextFormatFlags.VerticalCenter Or TextFormatFlags.Left
            Case Drawing.ContentAlignment.MiddleRight
                LabelAlign = TextFormatFlags.VerticalCenter Or TextFormatFlags.Right
            Case Drawing.ContentAlignment.TopCenter
                LabelAlign = TextFormatFlags.Top Or TextFormatFlags.HorizontalCenter
            Case Drawing.ContentAlignment.TopLeft
                LabelAlign = TextFormatFlags.Top Or TextFormatFlags.Left
            Case Drawing.ContentAlignment.TopRight
                LabelAlign = TextFormatFlags.Top Or TextFormatFlags.Right
        End Select
        If Text.Contains(vbNewLine) = False Then
            LabelAlign = LabelAlign Or TextFormatFlags.SingleLine
        End If
        If RightToLeft = Windows.Forms.RightToLeft.Yes Then
            LabelAlign = LabelAlign Or TextFormatFlags.RightToLeft
        End If
        If Not UseMnemonic Then
            LabelAlign = LabelAlign Or TextFormatFlags.NoPrefix
        End If
        Return LabelAlign
    End Function
    ''' <summary>
    ''' Reverse conten align.For example convert BottomRight to BottomLeft.
    ''' </summary>
    ''' <param name="ContentAlign">The content align that you want it to reverse.</param>
    Public Shared Function ReverseContentAlign(ByVal ContentAlign As ContentAlignment) As ContentAlignment
        Select Case ContentAlign
            Case ContentAlignment.BottomLeft
                Return ContentAlignment.BottomRight
            Case ContentAlignment.BottomRight
                Return ContentAlignment.BottomLeft
            Case ContentAlignment.MiddleLeft
                Return ContentAlignment.MiddleRight
            Case ContentAlignment.MiddleRight
                Return ContentAlignment.MiddleLeft
            Case ContentAlignment.TopLeft
                Return ContentAlignment.TopRight
            Case ContentAlignment.TopRight
                Return ContentAlignment.TopLeft
            Case Else
                Return ContentAlign
        End Select
    End Function
    ''' <summary>
    ''' Draw text with Right-To-Left compatibility.
    ''' </summary>
    ''' <param name="Parent">The control that you want to draw text on it.</param>
    ''' <param name="TextAlign">Align of text.</param>
    ''' <param name="Location">Location of text.</param>
    ''' <param name="RightToLeft">Is text RTL?</param>
    ''' <param name="UseMnemonic">Is UseMnemonic of text enabled?</param>
    ''' <param name="graphics">The Graphics object on which to draw.</param>
    ''' <param name="Text">The text to draw.</param>
    ''' <param name="font">The font used to draw text.</param>
    ''' <param name="ForeColor">The color used to draw the text.</param>
    Public Shared Sub DrawRTLText(ByVal Graphics As Graphics, ByVal Parent As Control, ByVal Text As String, ByVal ForeColor As Color, ByVal Font As Font, ByVal TextAlign As ContentAlignment, ByVal Location As Point, ByVal RightToLeft As RightToLeft, ByVal UseMnemonic As Boolean)
        Dim TOptions As TextOptions = GetRTLTextOptions(Graphics, Parent, Text, Font, TextAlign, Location, RightToLeft, UseMnemonic)
        TextRenderer.DrawText(Graphics, Text, Font, TOptions.Bounds, ForeColor, Color.Transparent, TOptions.Flags)
    End Sub
    ''' <summary>
    ''' Get TextOptions object of a Right-To-Left text that it will draw on Parent control.
    ''' </summary>
    ''' <param name="Parent">The control that you want to draw text on it.</param>
    ''' <param name="TextAlign">Align of text.</param>
    ''' <param name="Location">Location of text.</param>
    ''' <param name="RightToLeft">Is text RTL?</param>
    ''' <param name="UseMnemonic">Is UseMnemonic of text enabled?</param>
    ''' <param name="graphics">The Graphics object on which to draw.</param>
    ''' <param name="Text">The text to draw.</param>
    ''' <param name="font">The font used to draw text.</param>
    Public Shared Function GetRTLTextOptions(ByVal Graphics As Graphics, ByVal Parent As Control, ByVal Text As String, ByVal Font As Font, ByVal TextAlign As ContentAlignment, ByVal Location As Point, ByVal RightToLeft As RightToLeft, ByVal UseMnemonic As Boolean, Optional ByVal ForeColor As Color = Nothing) As TextOptions
        If ForeColor = Nothing Then
            ForeColor = Color.Black
        End If
        Dim TSize As Size = TextRenderer.MeasureText(Graphics, Text, Font)
        Dim TLeft As Integer = GetLeftForRTL(Parent, Location.X, TSize.Width)
        Return New TextOptions With {.Graphics = Graphics, .Text = Text, .Font = Font, .Flags = CommonTools.GetTextFormatFlags(If(RightToLeft = Windows.Forms.RightToLeft.Yes, ReverseContentAlign(TextAlign), TextAlign), RightToLeft, Text, UseMnemonic), .Bounds = New Rectangle(TLeft, Location.Y, TSize.Width, TSize.Height), .ForeColor = ForeColor}
    End Function

    ''' <summary>
    ''' Get TextOptions object of a Right-To-Left text that it will draw on Parent control.
    ''' </summary>
    ''' <param name="Label" >The label which you want its options.</param>
    ''' <param name="graphics">The Graphics object on which to draw.</param>
    Public Shared Function GetRTLTextOptions(ByVal Label As Label, Optional ByVal Graphics As Graphics = Nothing) As TextOptions
        Dim TLeft As Integer = GetLeftForRTL(Label.Parent, Label.Location.X, Label.Width)
        Return New TextOptions With {.Graphics = Graphics, .Text = Label.Text, .Font = Label.Font, .Flags = CommonTools.GetTextFormatFlags(If(Label.RightToLeft = Windows.Forms.RightToLeft.Yes, ReverseContentAlign(Label.TextAlign), Label.TextAlign), Label.RightToLeft, Label.Text, Label.UseMnemonic), .Bounds = New Rectangle(TLeft, Label.Location.Y, Label.Width, Label.Height), .ForeColor = Label.ForeColor}
    End Function
    ''' <summary>
    ''' Get left of a RTL text (if the control's RightToLeft be RightToLeft.Yes).
    ''' </summary>
    ''' <param name="Control">The control that you want its RTL left.</param>
    Shared Function GetLeftForRTL(ByVal Control As Control) As Integer
        If Control.RightToLeft = RightToLeft.Yes Then
            Return Control.Parent.Width - Control.Left - Control.Width
        Else
            Return Control.Left
        End If
    End Function
    ''' <summary>
    ''' Gets location of an RTL control.
    ''' </summary>
    ''' <param name="Control">The control that you want its RTL location.</param>
    Public Shared Function GetRTLLocation(ByVal Control As Control) As Point
        Dim Pt As New Point(Control.Left, Control.Top)
        If Control.RightToLeft = RightToLeft.Yes Then
            Pt.X = GetLeftForRTL(Control)
        End If
        Return Pt
    End Function
    ''' <summary>
    ''' Get left of a RTL text.
    ''' </summary>
    ''' <param name="ParentWidth">Widht of parent control.</param>
    ''' <param name="OriginalLeft">Left-To-Right left of text.</param>
    ''' <param name="Width">Width of text.</param>
    ''' <param name="IsRTL">Is text RTL?</param>
    Shared Function GetLeftForRTL(ByVal ParentWidth As Integer, ByVal OriginalLeft As Integer, ByVal Width As Integer, ByVal IsRTL As Boolean) As Integer
        If IsRTL Then
            Return ParentWidth - OriginalLeft - Width
        Else
            Return OriginalLeft
        End If
    End Function
    ''' <summary>
    ''' Get left of a RTL text.
    ''' </summary>
    ''' <param name="Parent">The control that you want to draw text on it.</param>
    ''' <param name="OriginalLeft">Left-To-Right left of text.</param>
    ''' <param name="Width">Width of text.</param>
    Shared Function GetLeftForRTL(ByVal Parent As Control, ByVal OriginalLeft As Integer, ByVal Width As Integer) As Integer
        If Parent.RightToLeft = RightToLeft.Yes Then
            Return Parent.Width - OriginalLeft - Width
        Else
            Return OriginalLeft
        End If
    End Function
    ''' <summary>
    ''' Get a LinearGradientBrush with Right-To-Left compatibility
    ''' </summary>
    ''' <param name="Gradient">Left-To-Right LinearGradientBrush.</param>
    ''' <param name="RightToLeft">Is RTL?</param>
    ''' <param name="Mode">Mode of LinearGradientBrush.For more information see <seealso cref="LinearGradientMode"/>.</param>
    Public Shared Function GetGradientForRTL(ByVal Gradient As LinearGradientBrush, ByVal RightToLeft As RightToLeft, ByVal Mode As LinearGradientMode) As LinearGradientBrush
        If RightToLeft = Windows.Forms.RightToLeft.No Then
            Return Gradient
        Else
            Return New LinearGradientBrush(Gradient.Rectangle, Gradient.LinearColors(1), Gradient.LinearColors(0), Mode)
        End If
    End Function
End Class
''' <summary>
''' A class for saving options of a text.Here,mostly use for RTL text drawing.
''' </summary>
''' <remarks></remarks>
Public Class TextOptions
    ''' <summary>
    ''' Gets or sets format of text.
    ''' </summary>
    Public Property Flags As TextFormatFlags
    ''' <summary>
    ''' Gets or sets graphic object that text will draw on it.
    ''' </summary>
    Public Property Graphics As Graphics
    ''' <summary>
    ''' Gets or sets text.
    ''' </summary>
    Public Property Text As String
    ''' <summary>
    ''' Gets or sets font of text.
    ''' </summary>
    Public Property Font As Font

    ''' <summary>
    ''' Gets or sets ForeColor of text.
    ''' </summary>
    Public Property ForeColor As Color

    ''' <summary>
    ''' Gets or sets the bounding rectangle within which to draw.
    ''' </summary>
    Public Property Bounds As Rectangle
End Class
Public Enum WallPaperLayout
    Tiled
    Centered
    Stretched
    Fill
    Fit
End Enum


''' <summary>
''' A class which add or remove your program from startup.
''' </summary>
Public Class StartUp
    Public Sub New()
        Registry = CurrentUser.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Run", True)
    End Sub
    Public Sub New(ByVal AllUsers As Boolean)
        If AllUsers = False Then
            Registry = CurrentUser.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Run", True)
        Else
            Registry = LocalMachine.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Run", True)
        End If
    End Sub
    Private Registry As RegistryKey
    Private Shared Registry2 As RegistryKey
    ''' <summary>
    ''' Add the program to startup.
    ''' </summary>
    ''' <param name="name">Program's name.</param>
    ''' <param name="arguments">Add arguments to program.</param>
    Sub Add(Optional ByVal Name As String = "Main", Optional ByVal Arguments As String = "")
        Registry.SetValue(Application.CompanyName + "," + Name + "," + Application.ProductName, Application.ExecutablePath + If(Arguments = "", "", " ") + Arguments)
    End Sub
#Region "PrivatesMethodes"
    Private Shared Sub SetRegistry2(ByVal AllUsers As Boolean)
        If AllUsers = False Then
            Registry2 = CurrentUser.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Run", True)
        Else
            Registry2 = LocalMachine.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Run", True)
        End If
    End Sub
    ''' <summary>
    ''' Remove the program from startup.
    ''' </summary>
    Private Shared Sub Remove(ByVal Arguments As String, ByVal AllUsers As Boolean)
        SetRegistry2(AllUsers)
        Dim AllStartUpPrograms = Registry2.GetValueNames
        For Each StartUpProgram In AllStartUpPrograms
            If Registry2.GetValue(StartUpProgram) = Application.ExecutablePath + If(Arguments = "", "", " ") + Arguments Then
                Registry2.DeleteValue(StartUpProgram)
            End If
        Next
        Dim StartUpLinks As New List(Of String)(Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.Startup)))
        Dim shell As New WshShell()
        For Each StartUpLink In StartUpLinks
            Dim fi As New FileInfo(StartUpLink)
            If fi.Extension.ToLower <> ".lnk" Then
                Continue For
            End If
            Dim link As IWshShortcut = DirectCast(shell.CreateShortcut(StartUpLink), IWshShortcut)
            If link.TargetPath.ToLower = (Application.ExecutablePath + If(Arguments = "", "", " ") + Arguments).ToLower Then
                IO.File.Delete(StartUpLink)
            End If
        Next
    End Sub
    ''' <summary>
    ''' Remove the program from startup.
    ''' </summary>
    Private Shared Sub Remove(ByVal AllUsers As Boolean)
        SetRegistry2(AllUsers)
        Dim AllStartUpPrograms = Registry2.GetValueNames
        For Each StartUpProgram In AllStartUpPrograms
            If Registry2.GetValue(StartUpProgram) = "" Then
                Continue For
            End If
            Dim JustName As String = Registry2.GetValue(StartUpProgram)
            JustName = JustName.Substring(0, JustName.ToLower().LastIndexOf(".exe") + 4)
            If JustName = Application.ExecutablePath Then
                Registry2.DeleteValue(StartUpProgram)
            End If
        Next
        Dim StartUpLinks As New List(Of String)(Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.Startup)))
        Dim shell As New WshShell()
        For Each StartUpLink In StartUpLinks
            Dim fi As New FileInfo(StartUpLink)
            If fi.Extension.ToLower <> ".lnk" Then
                Continue For
            End If
            Dim link As IWshShortcut = DirectCast(shell.CreateShortcut(StartUpLink), IWshShortcut)
            If link.TargetPath.Substring(0, link.TargetPath.ToLower().LastIndexOf(".exe") + 4).ToLower = Application.ExecutablePath.ToLower Then
                IO.File.Delete(StartUpLink)
            End If
        Next
    End Sub
    ''' <summary>
    ''' Returns a value that indicates the prgram is on startup.
    ''' </summary>
    Private Shared Function IsProgramOnStartUp(ByVal Arguments As String, ByVal AllUsers As Boolean) As Boolean
        SetRegistry2(AllUsers)
        Dim AllStartUpPrograms = Registry2.GetValueNames
        For Each StartUpProgram In AllStartUpPrograms
            If Registry2.GetValue(StartUpProgram) = Application.ExecutablePath + If(Arguments = "", "", " ") + Arguments Then
                Return True
            End If
        Next
        Dim StartUpLinks As New List(Of String)(Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.Startup)))
        Dim shell As New WshShell()
        For Each StartUpLink In StartUpLinks
            Dim fi As New FileInfo(StartUpLink)
            If fi.Extension.ToLower <> ".lnk" Then
                Continue For
            End If
            Dim link As IWshShortcut = DirectCast(shell.CreateShortcut(StartUpLink), IWshShortcut)
            If link.TargetPath.ToLower = (Application.ExecutablePath + If(Arguments = "", "", " ") + Arguments).ToLower Then
                Return True
            End If
        Next
        Return False
    End Function
    ''' <summary>
    ''' Returns a value that indicates the prgram is on startup.
    ''' </summary>
    Private Shared Function IsProgramOnStartUp(ByVal AllUsers As Boolean) As Boolean
        SetRegistry2(AllUsers)
        Dim AllStartUpPrograms = Registry2.GetValueNames
        For Each StartUpProgram In AllStartUpPrograms
            If Registry2.GetValue(StartUpProgram) = "" Then
                Continue For
            End If
            Dim JustName As String = Registry2.GetValue(StartUpProgram)
            JustName = JustName.Substring(0, JustName.ToLower().LastIndexOf(".exe") + 4).ToLower
            If JustName = Application.ExecutablePath.ToLower Then
                Return True
            End If
        Next
        Dim StartUpLinks As New List(Of String)(Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.Startup)))
        Dim shell As New WshShell()
        For Each StartUpLink In StartUpLinks
            Dim fi As New FileInfo(StartUpLink)
            If fi.Extension.ToLower <> ".lnk" Then
                Continue For
            End If
            Dim link As IWshShortcut = DirectCast(shell.CreateShortcut(StartUpLink), IWshShortcut)
            If link.TargetPath.Substring(0, link.TargetPath.ToLower().LastIndexOf(".exe") + 4).ToLower = Application.ExecutablePath.ToLower Then
                Return True
            End If
        Next
        Return False
    End Function
#End Region
    ''' <summary>
    ''' Remove the program from startup.
    ''' </summary>
    Shared Sub Remove(ByVal Arguments As String)
        Remove(Arguments, False)
        Remove(Arguments, True)
    End Sub
    ''' <summary>
    ''' Remove the program from startup.
    ''' </summary>
    Shared Sub Remove()
        Remove(False)
        Remove(True)
    End Sub
    ''' <summary>
    ''' Returns a value that indicates the prgram is on startup.
    ''' </summary>
    Shared Function IsProgramOnStartUp(ByVal Arguments As String) As Boolean
        Dim IsPOS As Boolean = IsProgramOnStartUp(Arguments, False)
        If IsPOS = False Then
            IsPOS = IsProgramOnStartUp(Arguments, True)
        End If
        Return IsPOS
    End Function
    ''' <summary>
    ''' Returns a value that indicates the prgram is on startup.
    ''' </summary>
    Shared Function IsProgramOnStartUp() As Boolean
        Dim IsPOS As Boolean = IsProgramOnStartUp(False)
        If IsPOS = False Then
            IsPOS = IsProgramOnStartUp(True)
        End If
        Return IsPOS
    End Function
End Class
Public Class WallPaperChanger
    Const SPI_SETDESKWALLPAPER As Integer = 20
    Const SPIF_UPDATEINIFILE As Integer = &H1
    Const SPIF_SENDWININICHANGE As Integer = &H2
    Private Shared tempPath As String = Path.Combine(Path.GetTempPath(), "Wallpaper.bmp")
    Public Shared Sub SetWallpaper(ByVal Image As Image, ByVal Layout As WallPaperLayout)
        Try
            Image.Save(tempPath, System.Drawing.Imaging.ImageFormat.Bmp)
        Catch ex As Exception
            tempPath += "_new_" + New Random().Next().ToString + ".bmp"
            Image.Save(tempPath, System.Drawing.Imaging.ImageFormat.Bmp)
        Finally
            tempPath = Path.Combine(Path.GetTempPath(), "Wallpaper.bmp")
        End Try
        Try
            Image.Dispose()
        Catch ex As Exception

        End Try
        Dim key As RegistryKey = Registry.CurrentUser.OpenSubKey("Control Panel\Desktop", True)
        Select Case Layout
            Case WallPaperLayout.Tiled
                key.SetValue("WallpaperStyle", 1.ToString())
                key.SetValue("TileWallpaper", 10.ToString())
            Case WallPaperLayout.Centered
                key.SetValue("WallpaperStyle", 1.ToString())
                key.SetValue("TileWallpaper", 0.ToString())
            Case WallPaperLayout.Stretched
                key.SetValue("WallpaperStyle", 2.ToString())
                key.SetValue("TileWallpaper", 0.ToString())
            Case WallPaperLayout.Fill
                key.SetValue("WallpaperStyle", 10.ToString())
                key.SetValue("TileWallpaper", 0.ToString())
            Case WallPaperLayout.Fit
                key.SetValue("WallpaperStyle", 6.ToString())
                key.SetValue("TileWallpaper", 0.ToString())
        End Select
        SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, tempPath, SPIF_UPDATEINIFILE Or SPIF_SENDWININICHANGE)
    End Sub
    Public Sub SetWallPaperDirectly(ByVal ImagePath As String, ByVal Layout As WallPaperLayout)
        Dim key As RegistryKey = Registry.CurrentUser.OpenSubKey("Control Panel\Desktop", True)
        Select Case Layout
            Case WallPaperLayout.Tiled
                key.SetValue("WallpaperStyle", 1.ToString())
                key.SetValue("TileWallpaper", 10.ToString())
            Case WallPaperLayout.Centered
                key.SetValue("WallpaperStyle", 1.ToString())
                key.SetValue("TileWallpaper", 0.ToString())
            Case WallPaperLayout.Stretched
                key.SetValue("WallpaperStyle", 2.ToString())
                key.SetValue("TileWallpaper", 0.ToString())
            Case WallPaperLayout.Fill
                key.SetValue("WallpaperStyle", 10.ToString())
                key.SetValue("TileWallpaper", 0.ToString())
            Case WallPaperLayout.Fit
                key.SetValue("WallpaperStyle", 6.ToString())
                key.SetValue("TileWallpaper", 0.ToString())
        End Select
        SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, ImagePath, SPIF_UPDATEINIFILE Or SPIF_SENDWININICHANGE)
    End Sub
    Public Shared Sub SetWallpaper(ByVal uri As Uri, ByVal Layout As WallPaperLayout)
        Dim s As IO.Stream = New System.Net.WebClient().OpenRead(uri.ToString())
        If s.Length = 0 Then
            Exit Sub
        End If
        Dim img As Image = Image.FromStream(s)
        SetWallpaper(img, Layout)
        s.Close()
    End Sub
    <DllImport("user32.dll", CharSet:=CharSet.Auto)> _
    Public Shared Function SystemParametersInfo(ByVal uiAction As UInt32, ByVal uiParam As UInt32, ByVal pvParam As String, ByVal fWinIni As UInt32) As Int32
    End Function
    Private Function GetCurrentWallpaper() As String
        ' The current wallpaper path is stored in the registry at HKCU\Control Panel\Desktop\WallPaper
        Dim rkWallPaper As RegistryKey = Registry.CurrentUser.OpenSubKey("Control Panel\Desktop", False)
        Dim WallpaperPath As String = rkWallPaper.GetValue("WallPaper").ToString()
        rkWallPaper.Close()
        ' Return the current wallpaper path
        Return WallpaperPath
    End Function

    '#Region "Fade"
    '    Dim owall As Bitmap
    '    Dim WithEvents tmrBlend As New Timer With {.Interval = 1}
    '    Dim current_alpha As Single = 0.0
    '    Dim increase As Boolean = True
    '    'The speed is from 0 to 1
    '    Private Property Speed As Single = 0.1
    '    Private Property Layout As WallPaperLayout = WallPaperLayout.Stretched
    '    Dim ChangingWP As Bitmap
    '    Dim LastThread As Threading.Thread
    '    Dim Ani As New Animation
    '    Private Sub SetWall(ByVal path As String)
    '        If LastThread IsNot Nothing Then
    '            LastThread.Abort()
    '        End If
    '        ChangingWP = Bitmap.FromFile(path)
    '        owall = New Bitmap(ChangingWP.Width, ChangingWP.Height)
    '        Dim gr As Graphics = Graphics.FromImage(owall)
    '        Dim oImg As Image = Image.FromFile(GetCurrentWallpaper)
    '        gr.DrawImage(oImg, New Rectangle(New Point(0, 0), New Size(ChangingWP.Width, ChangingWP.Height)))
    '        oImg.Dispose()
    '        current_alpha = 0
    '        LastThread = Ani.ImageFadeAnimation(Me, "WallPaper", ChangingWP, 0, Speed, True, False)
    '        FramesPath.Clear()
    '        cf = 0
    '        If IO.Directory.Exists(IO.Path.GetTempPath() + "Frames\") = False Then
    '            IO.Directory.CreateDirectory(IO.Path.GetTempPath() + "Frames\")
    '        End If
    '        For i = 0 To Ani.frames.Count - 1
    '            Dim ImgPath As String = IO.Path.GetTempPath() + "Frames\" + i.ToString + ".bmp"
    '            Ani.frames(i).Save(ImgPath, System.Drawing.Imaging.ImageFormat.Bmp)
    '            Ani.frames(i).Dispose()
    '            FramesPath.Add(ImgPath)
    '        Next
    '        tmrBlend.Enabled = True
    '    End Sub

    '    Dim FramesPath As New List(Of String)
    '    Private Property WallPaper As Image
    '        Get
    '            Return owall
    '        End Get
    '        Set(ByVal value As Image)
    '            SetWallpaper(value, Layout)
    '        End Set
    '    End Property
    '    Dim cf As Integer = 0
    '    Private Sub tmrBlend_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrBlend.Tick
    '        If cf = FramesPath.Count Then
    '            cf = 0
    '            tmrBlend.Enabled = False
    '            Exit Sub
    '        End If
    '        SetWallPaperDirectly(FramesPath(cf), Layout)
    '        cf += 1
    '        Exit Sub
    '        Dim i1 As Bitmap = owall.Clone
    '        Dim i2 As New Bitmap(ChangingWP)

    '        Dim g As Graphics = Graphics.FromImage(i1)

    '        Dim cm As New Imaging.ColorMatrix(New Single()() { _
    '                                                         New Single() {1, 0, 0, 0, 0}, _
    '                                                         New Single() {0, 1, 0, 0, 0}, _
    '                                                         New Single() {0, 0, 1, 0, 0}, _
    '                                                         New Single() {0, 0, 0, current_alpha, 0}, _
    '                                                         New Single() {0, 0, 0, 0, 1}})

    '        Dim ia As New Imaging.ImageAttributes
    '        ia.SetColorMatrix(cm, Imaging.ColorMatrixFlag.Default, Imaging.ColorAdjustType.Bitmap)

    '        g.DrawImage(i2, New Rectangle(0, 0, i2.Width, i2.Height), 0, 0, i2.Width, i2.Height, GraphicsUnit.Pixel, ia)
    '        g.Dispose()

    '        If increase Then
    '            current_alpha += Speed
    '        Else
    '            current_alpha -= Speed
    '        End If

    '        SetWallpaper(i1, Layout)
    '        If current_alpha >= 1 Then
    '            current_alpha = 1
    '            tmrBlend.Enabled = False
    '            SetWallpaper(ChangingWP, Layout)
    '        ElseIf current_alpha <= 0 Then
    '            current_alpha = 0
    '            tmrBlend.Enabled = False
    '        End If
    '    End Sub
    '#End Region

End Class